/*
 *  Filename:lsv_conf.h
 *  Description:
 *
 *  Created on: 2017年3月2日
 *  Author: Asdf(825674301)
 */

#ifndef __LSV_CONF_H_
#define __LSV_CONF_H_

#include <stdint.h>

#define __PAGE_CRC32__

// -------------------------------------------------------------------------
// {{ global
#define LSV_MAX_VOLUME_SIZE (((unsigned long int)1)<<48)//256T

#define LSV_PAGE_SIZE      (4096)
#define LSV_CHUNK_SIZE     (1<<20) //1M
#define LSV_MAX_CHUNK_NUM  (LSV_MAX_VOLUME_SIZE/LSV_CHUNK_SIZE)

#define LSV_MAX_STRING_LEN (256)

#define LSV_PRIM_CHUNK_ID  (0)
#define LSV_PRIM_CHUNK_NUM (1)
#define LSV_CHUNK_NULL     LSV_PRIM_CHUNK_ID
#define LSV_THIS_VOL_INO   (0)

#define CHECK_CRC 1

// global }}

// -------------------------------------------------------------------------
// {{ write buffer

// iscsi io depth
// #define IO_DEPTH    32
#define IO_FRAG_MAX 5

#define WBUF_CHUNK_NUM 8

#define WAL_SEGMENT_CHUNK_NUM 16

#define WBUF_USE_CHUNK   1
#define WBUF_USE_PREPARE 1
#define WBUF_CHECK_CRC   1
#define WBUF_USE_LTABLE  1

// write buffer }}


//bitmap
#define LSV_METADATA_RATIO (512)

#define LSV_USE_HUGE_PAGE               0
#define LSV_MAX_IO_PER_VOLUME           2048

//temp
#define LSV_STORAGE_SIZE (((lsv_u64_t) 1 << 40) * 256)

//init
typedef enum __lsv_load_t {
        LSV_SYS_CREATE    = 0,
        LSV_SYS_LOAD      = 1,
        LSV_SYS_RECOVERY  = 2,
} lsv_load_t;

// for fuse, volume storage
#define LSV_VOLUME_STORAGE_FILE_PREFIX "/mnt/lsv-volume/data/file"
#define LSV_VOLUME_STORAGE_META_DIR    "/mnt/lsv-volume/meta/"

#define LSV_LOG_FILE_PATH "/mnt/lsv-volume/log/"

// TODO
#define LSV_STORAGE_TYPE_SSD   (0)
#define LSV_STORAGE_TYPE_HDD   (1)
#define LSV_STORAGE_TYPE_COUNT (2)

#define LSV_PRIM_CHUNK_TYPE      LSV_STORAGE_TYPE_SSD
#define LSV_VOLGC_STORAGE_TYPE   LSV_STORAGE_TYPE_SSD
#define LSV_BITMAP_STORAGE_TYPE  LSV_STORAGE_TYPE_SSD
#define LSV_WBUFFER_STORAGE_TYPE LSV_STORAGE_TYPE_SSD
#define LSV_RCACHE_STORAGE_TYPE  LSV_STORAGE_TYPE_SSD
#define LSV_GC_STORAGE_TYPE      LSV_STORAGE_TYPE_SSD
#define LSV_LOG_LOG_STORAGE_TYPE LSV_STORAGE_TYPE_HDD

//volume
#define LSV_VOLGC_MALLOC_TYPE      (2)     // 1 from firstly extend 2 from firstly reuse
#define LSV_VOLGC_AVACHK_LIST_NUM  (3)     //min 2
#define LSV_VOLGC_MALLOC_CHUNK_NUM (512)   //malloc chunk num each extend

#define LSV_STORAGE_AVA_RATIO    (0.8)

//log
#define LSV_GC_LOGCTRL_TAB_NAME_BASE "LSV_LOGGC_LOGCTRL_TAB"

#define LSV_GC_DIRTY_RATIO    (0.25)  // the dirty data ratio in log to gc. LSV_GC_GC_CHUNK_TYPE==1, more than 0.5;LSV_GC_GC_CHUNK_TYPE==2, more than 0
#define LSV_GC_NUMTIMES       (2)     // a log gc number of times

//#define LSV_LOGGC_CHECK_QUEUE_SIZE  (1024)
#define LSV_GC_CHECK_QUEUE_FULLGC_ADD_TASK_MAX   (10)
#define LSV_GC_CHECK_QUEUE_RECOVERY_ADD_TASK_MAX (30)

#define LSV_GC_CHECK_QUEUE_SIZE  (1024*1024) //lsv volume size 1T
#define LSV_GC_HEAP_SIZE         (1023)  // 2^-1,more than 2*1/(1-LSV_LOGGC_GC_RATIO) if half full can gc a log
#define LSV_GC_FULLGC_SIZE       (512)   // fullgc log number wvery time,half of LSV_LOGGC_GC_HEAP_SIZE may be good.Because storage half of LSV_LOGGC_GC_HEAP_SIZE when gc_heap is full
#define LSV_GC_LOGCTRL_READ_TYPE (1)     // 1 from stroage 2 from rcache
#define LSV_GC_LOGCTRL_HLOG_TYPE (2)     // 1 in memory 2 read in check
#define LSV_GC_GC_CHUNK_TYPE     (2)     // 1 for gc complete chunk to a not whole chunk , 2 for gc chunk ,that may be gc a part,to a whole chunk

#define LSV_GC_FULLGC_EXIT_CKECK_QUEUE_SIZE_MUL (3)
//#define LSV_GC_FULLGC_EXIT_CKECK_QUEUE_SIZE (LSV_GC_FULLGC_EXIT_CKECK_QUEUE_SIZE_MUL*LSV_GC_CHECK_QUEUE_SIZE)
#define LSV_GC_FULLGC_INTERVAL        ((unsigned long int)10000)  // do fullgc according to gc count
#define LSV_GC_FULLGC_TIMER_INTERVAL  (10*60)  // do fullgc according to timer

//write buffer
#define LSV_WBUF_PAGE_SIZE  (LSV_PAGE_SIZE)
#define LSV_WBUF_PAGE_NUM   (LSV_CHUNK_SIZE / LSV_WBUF_PAGE_SIZE)

#define LSV_WBUF_CHUNK_SIZE (LSV_CHUNK_SIZE)

#define LSV_WBUF_CHUNK_NUM       (1)
#define LSV_WBUF_CHUNK_GROUP_MAX (32)

/**
 * wbuf chunk状态：
 *
 * CLEAN --[push] -> COMMIT_PRE --[commit]-> COMMIT_POST --[reuse]-> CLEAN
 * free_list: CLEAN | COMMIT_POST
 * wait_list: COMMIT_PRE | COMMIT_POST
 *
 */
#define LSV_WBUF_CHUNK_CLEAN       (0)
#define LSV_WBUF_CHUNK_PRE_COMMIT  (1)
#define LSV_WBUF_CHUNK_POST_COMMIT (2)

// #define LSV_WBUF_MAX_TIMESTAMP (0x7fffffffffffffff)

typedef enum {
        LSV_WBUF_CHUNK_STATUS_INIT = 0,     // page_idx: 0
        LSV_WBUF_CHUNK_STATUS_NOTEMPTY,     // page_idx: [1-254]
        LSV_WBUF_CHUNK_STATUS_FULL,         // page_idx: 255
        LSV_WBUF_CHUNK_STATUS_WAIT,         // page_idx: 255
        LSV_WBUF_CHUNK_STATUS_READY,        // page_idx: 255
} lsv_wbuf_chunk_status_t;

// #define LSV_WBUF_CHUNK_ERR  (-1)
// SYNC INTERVAL FOR SYNC CHUNK_BUF->METAINFO, us
// #define LSV_WBUF_SYNC_INTERVAL (5000)
// #define LSV_WBUF_REMALLOC_INTERVAL (24*60*60)

//rcache buffer
#define LSV_RCACHE_PAGE_SIZE (LSV_PAGE_SIZE)
#define LSV_RCACHE_PAGE_NUM  (LSV_CHUNK_SIZE / LSV_WBUF_PAGE_SIZE)

// page cache
#define LSV_RCACHE_PAGE_NUM_MAX (64 * LSV_RCACHE_PAGE_NUM)

// chunk cache (memory)
#define LSV_RCACHE_CHUNK_NUM_MAX (64)

// chunk cache (SSD)
#define LSV_RCACHE_CHUNK_NUM_MAX_L2 (4096)

//io_list 统计的最大io数量
#define LSV_RCACHE_IOTRACE_NUM (255)
//每255个io，最大的chunk数量，可以load chunk，大于这个数，则load page#define LSV_RCACHE_CHUNK_NUMS_PER_CIRCLE (40)
#define LSV_RCACHE_CHUNK_NUMS_PER_CIRCLE (20)
//#define LSV_RCACHE_CHUNK_NUMS_PER_CIRCLE_WITH_RIO (LSV_RCACHE_CHUNK_NUMS_PER_CIRCLE/2)
#define LSV_RCACHE_CHUNK_NUMS_PER_CIRCLE_WITH_RIO (16)
#define LSV_RCACHE_IO_NUM_LEAST (100)
#define LSV_RCACHE_LOAD_CHUNK_RIO (128 * 1024)
//#define __NO_CACHE__

//remote mirror
#define LSV_RM_CONF_PATH "/mnt/lsv_volume/conf/conf.h"
//#define LSV_RM_MASTER (0)
//#define LSV_RM_SLAVE  (1)
//#define LSV_RM_MASTER_LISTEN_PORT ("60001")
//#define LSV_RM_SLAVE_ADDR ("127.0.0.1")

//snapshot
#define LSV_CREATE_SNAPSHOT  (_IOW('E', 1, 64))
#define LSV_REVERT_SNAPSHOT  (_IOW('E', 2, 64))
#define LSV_DELETE_SNAPSHOT  (_IOW('E', 3, 64))
#define LSV_PRINT_SNAPSHOT   (_IOW('E', 4, 64))

// {{ feature on/off

#define LSV_FEATURE_WAL2                0x00000001
#define LSV_FEATURE_SPIRAL_WRITE        0x00000002
#define LSV_FEATURE_WBUF_PIPELINE       0x00000004
#define LSV_FEATURE_WBUF_READ           0x00000008

#define LSV_FEATURE_LOG                 0x00000010

#define LSV_FEATURE_BITMAP              0x00000020
#define LSV_FEATURE_BITMAP_GROUP_COMMIT 0x00000040
#define LSV_FEATURE_BITMAP_GC_VALUE_UP  0x00000080

#define LSV_FEATURE_GC                  0x00000100

// internals

#define ENABLE_WAL          0
#define ENABLE_WBUF_MQ      0
#define ENABLE_WBUF_LOAD    1

// for test
#define ENABLE_ONLY_4K      0

extern uint32_t lsv_feature;

// }}

// log/bitmap pipeline
#define PIPELINE_LOG_MAX    32
#define PIPELINE_BITMAP_MAX 1024

//slog pos to chunk_offset
//#define lsv_log_slogpos2chkoffset(pos) ((pos + 1) * LSV_PAGE_SIZE)
#define lsv_log_slogpos2chkoffset(pos) ((pos) + 1)

#define CHUNKOFF2PAGEIDX(chunk_off) ((chunk_off) / LSV_PAGE_SIZE - 1)

#define PRINT_PAGE(off, size, ret, name) do {        \
        YASSERT((size) <= LSV_PAGE_SIZE);     \
        uint64_t lba = OFF2LBA(off);          \
        uint32_t A = (off) % LSV_PAGE_SIZE;   \
        uint32_t B = (size);                  \
        uint32_t C = LSV_PAGE_SIZE - A - B;   \
        DINFO("lba %llu <%u, %u, %u> off <%llu, %u> ret %d %s\n", (LLU)lba, A, B, C, (LLU)(off), (size), \
             (ret),   \
             (name)); \
} while(0)

#define PRINT_PAGE_CRC(lba, chunk_id, page, crc1, crc2) do { \
        YASSERT((lba) % LSV_PAGE_SIZE == 0); \
        YASSERT((page) >= 0 && (page) <= 254); \
        DINFO("lba %llu chunk_id %u page %u crc %u %u\n", (LLU)(lba), (chunk_id), (page), (crc1), (crc2)); \
        if ((crc1) != 0 && (crc2) != 0) {  \
                YASSERT((crc1) == (crc2)); \
        } \
} while(0)

#define CHUNK_HISTORY(tag, logctrl) do { \
        YASSERT((logctrl)->head.page_count >= (logctrl)->lp_bm.inactive_page_count); \
        DINFO(":chunk_history :%s chunk_id %u page %u inactive %u gc_value %u gc_count %u\n",    \
                (tag),                                \
                (logctrl)->chunk_id,                  \
                (logctrl)->head.page_count,           \
                (logctrl)->lp_bm.inactive_page_count, \
                (logctrl)->gc_value,                  \
                (logctrl)->gc_count);                 \
} while(0)

#define PRINT_GC_STAT(lsv_info) do { \
        lsv_log_info_t *log_info = (lsv_info)->log_info; \
        lsv_gc_context_t *gc_context = log_info->gc_context; \
        DINFO_NOP(":gc stat cq %u heap %u hash %u os <%u,%u>\n",  \
                gc_context->check_queue.count,              \
                gc_context->gc_heap.count,                  \
                gc_context->log_ctrl_tab->num_of_entries,   \
                gc_context->old_storage.count,              \
                gc_context->old_storage.ready_chunk.count); \
} while(0)

#endif /* __LSV_CONF_H_ */
